//! Basic tests for Zig syscall implementation
//! SPDX-License-Identifier: MPL-2.0

const std = @import("std");
const testing = std.testing;
const lib = @import("../src/lib.zig");
const SyscallReturn = @import("../src/return.zig").SyscallReturn;
const SyscallError = @import("../src/error.zig").SyscallError;
const Context = @import("../src/context.zig").Context;

// Mock context for testing
const MockContext = struct {
    const Self = @This();
    
    pub fn user_space(self: *Self) MockUserSpace {
        _ = self;
        return MockUserSpace{};
    }
    
    pub fn current_process(self: *Self) MockProcess {
        _ = self;
        return MockProcess{};
    }
    
    pub fn current_thread(self: *Self) MockThread {
        _ = self;
        return MockThread{};
    }
};

const MockUserSpace = struct {
    pub fn read_bytes(self: @This(), addr: u64, buf: []u8) !usize {
        _ = self;
        _ = addr;
        _ = buf;
        return 0;
    }
    
    pub fn write_bytes(self: @This(), addr: u64, data: []const u8) !usize {
        _ = self;
        _ = addr;
        _ = data;
        return data.len;
    }
};

const MockProcess = struct {
    pub fn pid(self: @This()) u32 {
        _ = self;
        return 1234;
    }
};

const MockThread = struct {
    pub fn tid(self: @This()) u32 {
        _ = self;
        return 5678;
    }
};

test "syscall dispatcher basic functionality" {
    var mock_ctx = MockContext{};
    var ctx = Context.from_mock(&mock_ctx);
    
    // Test invalid syscall number
    const result = lib.handle_syscall(999999, 0, 0, 0, 0, 0, 0, &ctx);
    try testing.expect(result == @intFromEnum(SyscallError.ENOSYS));
}

test "getpid syscall" {
    var mock_ctx = MockContext{};
    var ctx = Context.from_mock(&mock_ctx);
    
    // Test getpid (syscall 39)
    const result = lib.handle_syscall(39, 0, 0, 0, 0, 0, 0, &ctx);
    try testing.expect(result == 1234); // Should return mock PID
}

test "syscall error handling" {
    // Test that error codes are properly converted
    const err_return = SyscallReturn.error_return(SyscallError.EINVAL);
    try testing.expect(err_return == @intFromEnum(SyscallError.EINVAL));
    
    const success_return = SyscallReturn.success(42);
    try testing.expect(success_return == 42);
}

test "syscall statistics" {
    // Reset stats
    lib.reset_stats();
    
    var mock_ctx = MockContext{};
    var ctx = Context.from_mock(&mock_ctx);
    
    // Make some syscalls
    _ = lib.handle_syscall(39, 0, 0, 0, 0, 0, 0, &ctx); // getpid
    _ = lib.handle_syscall(999, 0, 0, 0, 0, 0, 0, &ctx); // invalid
    
    const stats = lib.get_stats();
    try testing.expect(stats.total_calls == 2);
    try testing.expect(stats.error_calls == 1);
}

test "memory management syscalls" {
    var mock_ctx = MockContext{};
    var ctx = Context.from_mock(&mock_ctx);
    
    // Test mmap (syscall 9) - should return ENOSYS for now
    const mmap_result = lib.handle_syscall(9, 0, 4096, 3, 34, 0, 0, &ctx);
    try testing.expect(mmap_result == @intFromEnum(SyscallError.ENOSYS));
    
    // Test munmap (syscall 11) - should return ENOSYS for now
    const munmap_result = lib.handle_syscall(11, 0x1000, 4096, 0, 0, 0, 0, &ctx);
    try testing.expect(munmap_result == @intFromEnum(SyscallError.ENOSYS));
}

test "file system syscalls" {
    var mock_ctx = MockContext{};
    var ctx = Context.from_mock(&mock_ctx);
    
    // Test read (syscall 0) - should return ENOSYS for now
    const read_result = lib.handle_syscall(0, 0, 0x1000, 100, 0, 0, 0, &ctx);
    try testing.expect(read_result == @intFromEnum(SyscallError.ENOSYS));
    
    // Test write (syscall 1) - should return ENOSYS for now
    const write_result = lib.handle_syscall(1, 1, 0x1000, 100, 0, 0, 0, &ctx);
    try testing.expect(write_result == @intFromEnum(SyscallError.ENOSYS));
}

test "time syscalls" {
    var mock_ctx = MockContext{};
    var ctx = Context.from_mock(&mock_ctx);
    
    // Test time (syscall 201) - should return current timestamp
    const time_result = lib.handle_syscall(201, 0, 0, 0, 0, 0, 0, &ctx);
    try testing.expect(time_result > 0); // Should be a valid timestamp
    
    // Test gettimeofday (syscall 96) - should succeed with null pointer
    const gettimeofday_result = lib.handle_syscall(96, 0, 0, 0, 0, 0, 0, &ctx);
    try testing.expect(gettimeofday_result == 0); // Should succeed
}